﻿using System.Collections.Generic;

namespace Raven
{
    public abstract class RavenProjectile : MovingEntity
    {
        protected EntityPool _pool;
        private DisplayObject _displayObject;

        protected int _shooterID;
        protected Vector2 _target;
        protected RavenGame _world;
        protected Vector2 _origin;
        protected Fix _damageInflicted;
        protected bool _dead;

        protected bool _impacted;

        //the position where this projectile impacts an object
        protected Vector2 _impactPoint;
        protected Fix _timeOfCreation;

        protected RavenBot GetClosestIntersectingBot(Vector2 from, Vector2 to)
        {
            RavenBot ClosestIntersectingBot = null;
            Fix ClosestSoFar = Fix.MaxValue;

            //iterate through all entities checking against the line segment FromTo
            foreach (var curBot in _world.GetAllBots())
            {
                //make sure we don't check against the shooter of the projectile
                if (curBot.ID() != _shooterID)
                {
                    //if the distance to FromTo is less than the entity's bounding radius then
                    //there is an intersection
                    if (Geometry.DistToLineSegment(from, to, curBot.Pos()) < curBot.BRadius())
                    {
                        //test to see if this is the closest so far
                        Fix Dist = (curBot.Pos() - _origin).sqrMagnitude;

                        if (Dist < ClosestSoFar)
                        {
                            Dist = ClosestSoFar;
                            ClosestIntersectingBot = curBot;
                        }
                    }
                }
            }

            return ClosestIntersectingBot;
        }

        protected LinkedList<RavenBot> GetListOfIntersectingBots(Vector2 from,
            Vector2 to)
        {
            LinkedList<RavenBot> hits = new LinkedList<RavenBot>();
            //iterate through all entities checking against the line segment FromTo
            foreach (var curBot in _world.GetAllBots())
            {
                //make sure we don't check against the shooter of the projectile
                if (curBot.ID() != _shooterID)
                {
                    //if the distance to FromTo is less than the entities bounding radius then
                    //there is an intersection so add it to hits
                    if (Geometry.DistToLineSegment(from, to, curBot.Pos()) < curBot.BRadius())
                    {
                        hits.AddLast(curBot);
                    }
                }
            }

            return hits;
        }

        public RavenProjectile(EntityType type, Vector2 target, //the target's position
            RavenGame world, //a pointer to the world data
            int ShooterID, //the ID of the bot that fired this shot
            Vector2 origin, //the start position of the projectile
            Vector2 heading, //the heading of the projectile
            int damage, //how much damage it inflicts
            Fix bRadius,
            Fix MaxSpeed,
            Fix mass,
            Fix MaxForce) : base(type, origin, bRadius, Vector2.zero, MaxSpeed, heading, mass, 0,
            MaxForce)
        {
            _target = target;
            _dead = false;
            _impacted = false;
            _world = world;
            _damageInflicted = damage;
            _origin = origin;
            _shooterID = ShooterID;
            _timeOfCreation = _world.GetTimer().currentTime;

            CreateDisplayObject();
        }
        
         

        public Vector2 GetOrigin()
        {
            return _origin;
        }

        public Vector2 GetImpactPoint()
        {
            return _impactPoint;
        }

        public virtual void Update()
        {
            _displayObject?.Update();
        }

        public override void Destroy()
        {
            _displayObject?.Destroy();
        }

        public bool isDead()
        {
            return _dead;
        }

        //true if the projectile has impacted but is not yet dead (because it
        //may be exploding outwards from the point of impact for example)
        public bool HasImpacted()
        {
            return _impacted;
        }

        private void CreateDisplayObject()
        {
            _displayObject = DisplayObjectFactory.CreateDisplayObject(this);
            _displayObject?.Start();
        }
    }
}